﻿using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore;
using System.Data;
using System.Linq.Expressions;
using Mes.Domain.BoundedContext.Entities;
using Mes.Infrastructure.Data.BoundedContext.RepositoryBase;
using Mes.Domain.BoundedContext;
using System.Reflection;

namespace Mes.Infrastructure.Data.BoundedContext.Repositories
{
    public class Repository<T, TId> : IRepository<T, TId> where T : class, IEntityBase<TId>
    {
        protected bool IsSoftDelete { get; } = typeof(ISoftDelete).GetTypeInfo().IsAssignableFrom(typeof(T));

        public string GetTypeof()
        {
            return typeof(T).Name; //通过typeof可以知道泛型的名字
        }

        /// <summary>
        /// Db上下文
        /// </summary>
        private MesDbContext Context { get; }

        /// <summary>
        /// 实体集合
        /// </summary>
        private DbSet<T> DbSet { get; }


        public Repository(MesDbContext context)
        {
            Context = context;
            DbSet = Context.Set<T>();
        }

        /// <summary>
        /// 事务
        /// </summary>
        /// <returns></returns>
        public IDbContextTransaction BeginTransaction()
        {
            return Context.Database.BeginTransaction();
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <returns></returns>
        public IQueryable<T> Query()
        {
            return DbSet;
        }

        /// <summary>
        /// 条件查询
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual IQueryable<T> Filter(Expression<Func<T, bool>> predicate)
        {
            return DbSet.Where<T>(predicate).AsQueryable<T>();
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="total"></param>
        /// <param name="index"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public virtual List<T> Filter(Expression<Func<T, bool>> filter, Expression<Func<T, dynamic>> orderBy, SortOrder sortOrder, out int total, int index = 0,
            int size = 50)
        {
            var skipCount = index * size;
            var resetSet = filter != null ? DbSet.Where<T>(filter).AsQueryable<T>() : DbSet.AsQueryable();
            var result = resetSet?.ToList();
            if (result != null && result.Any())
            {
                switch (sortOrder)
                {
                    case SortOrder.Ascending:
                        result = result.OrderBy(orderBy.Compile()).ToList();
                        break;
                    case SortOrder.Descending:
                        result = result.OrderByDescending(orderBy.Compile()).ToList();
                        break;
                }
            }
            total = result.Count();
            result = skipCount == 0 ? result.Skip(0).Take(size).ToList() : result.Skip((index - 1) * size).Take(size).ToList();
            return result;
        }

        public bool Exists(Expression<Func<T, bool>> predicate)
        {
            return DbSet.Any(predicate);
        }

        public virtual Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate)
        {
            return DbSet.AnyAsync(predicate);
        }

        /// <summary>
        /// 查询数量
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public int Count(Expression<Func<T, bool>> predicate)
        {
            return DbSet.Count(predicate);
        }

        /// <summary>
        /// 查询数量（异步）
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual Task<int> CountAsync(Expression<Func<T, bool>> predicate)
        {
            return DbSet.CountAsync(predicate);
        }

        public virtual T Find(Expression<Func<T, bool>> predicate)
        {
            return DbSet.FirstOrDefault(predicate);
        }

        public virtual Task<T> FindAsync(Expression<Func<T, bool>> predicate)
        {
            return DbSet.FirstOrDefaultAsync(predicate);
        }



        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="entity"></param>
        public void Add(T entity)
        {
            DbSet.Add(entity);          
        }

        /// <summary>
        /// 新增(异步)
        /// </summary>
        /// <param name="entity"></param>
        public virtual async Task AddAsync(T entity)
        {
            await DbSet.AddAsync(entity);
        }

        /// <summary>
        /// 批量新增
        /// </summary>
        /// <param name="entity"></param>
        public void AddRange(IEnumerable<T> entity)
        {
            DbSet.AddRange(entity);
        }

        /// <summary>
        /// 批量新增(异步)
        /// </summary>
        /// <param name="entity"></param>
        public virtual async Task AddRangeAsync(IEnumerable<T> entity)
        {
          await DbSet.AddRangeAsync(entity);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity"></param>
        public void Delete(T entity)
        {
            if (IsSoftDelete)
            {
                Tracking(entity);
                ((ISoftDelete)entity).IsDeleted = true;
            }
            else
            {
                DbSet.Remove(entity);
            }
        }

        /// <summary>
        /// 按照条件删除
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual void Delete(Expression<Func<T, bool>> predicate)
        {
            if (IsSoftDelete)
            {
                var items = DbSet.Where(predicate);
                foreach (var item in items)
                {
                    Tracking(item);
                    ((ISoftDelete)item).IsDeleted = true;
                }
            }
            else
            {
                var items = DbSet.Where(predicate);
                foreach (var item in items)
                {
                    DbSet.Remove(item);
                }
            }
        }

        public virtual Task DeleteAsync(Expression<Func<T, bool>> predicate)
        {
            if (IsSoftDelete)
            {
                var items = DbSet.Where(predicate);
                foreach (var itm in items)
                {
                    Tracking(itm);
                    ((ISoftDelete)itm).IsDeleted = true;
                }
            }
            else
            {
                var items = DbSet.Where(predicate);
                foreach (var item in items)
                {
                    DbSet.Remove(item);
                }
            }
            return Task.CompletedTask;
        }

        public void Tracking(T entity)
        {
            DbSet.Attach(entity);
        }

        public virtual void Update(T t)
        {
            try
            {
                var entry = Context.Entry(t);
                DbSet.Attach(t);
                entry.State = EntityState.Modified;
            }
            catch (DBConcurrencyException ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 同步保存
        /// </summary>
        public int Save()
        {
            return Context.SaveChanges();
        }

        public Task<int> SaveAsync()
        {
            return Context.SaveChangesAsync();
        }
    }

    /// <summary>
    /// Repository实现类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Repository<T> : Repository<T, int>, IRepository<T> where T : class, IEntityBase<int>
    {
        public Repository(MesDbContext context) : base(context)
        {
        }
    }
}
